package cn.colat.micse.common.aop;

import com.alibaba.fastjson2.JSONObject;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;

/**
 * 日志AOP 打印请求日志
 */
@Slf4j
@Aspect
@Component
public class RequestLogAop {
    @Around(value = "execution(* cn.colat.micse.*.controller..*.* (..))")
    public Object outputRequestLog(ProceedingJoinPoint joinPoint) throws Throwable {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert attributes != null;
        HttpServletRequest request = attributes.getRequest();
        String title = getApiOperation(joinPoint);
        String httpMethod = request.getMethod();
        String uri = request.getRequestURI();
        String ip = getIp(request);
        String queryString = getQueryString(request);
        String body = getBody(request, joinPoint);
        log.info("Request Log: {} ip:[{}] method:[{}] uri: {} {}{}", title, ip, httpMethod, uri, queryString, body);
        return joinPoint.proceed();
    }

    private String getIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Real-IP");
        if (!StringUtils.hasLength(ip)) {
            ip = request.getRemoteHost();
        }
        return ip;
    }

    private String getQueryString(HttpServletRequest request) {
        String queryString = request.getQueryString();
        if (StringUtils.hasLength(queryString)) {
            queryString = "queryString: [" + queryString + "] ";
        } else {
            queryString = "";
        }
        return queryString;
    }

    private String getBody(HttpServletRequest request, ProceedingJoinPoint joinPoint) {
        String contextType = getContextType(request);
        if ("application/json".equals(contextType)) {
            if (request.getMethod().equalsIgnoreCase("POST")) {
                if (joinPoint.getArgs().length > 0) {
                    try {
                        String json = JSONObject.toJSONString(joinPoint.getArgs()[0]);
                        return "Body: " + json;
                    } catch (Exception e) {
                        e.printStackTrace();
                        log.error("请求体解析错误：{} e:{}", joinPoint.getArgs(), e.getMessage());
                    }
                }
            }
        }
        return "";
    }

    private String getContextType(HttpServletRequest request) {
        String contentType = request.getContentType();
        if (!StringUtils.hasLength(contentType)) {
            contentType = "";
        }
        return contentType;
    }

    private String getApiOperation(ProceedingJoinPoint joinPoint) {
        String title = "";
        // 获取类上的说明
        try {
            Class<?> controllerClass = joinPoint.getSignature().getDeclaringType();
            if (controllerClass.isAnnotationPresent(Api.class)) {
                Api apiAnno = controllerClass.getAnnotation(Api.class);
                String[] tags = apiAnno.tags();
                if (tags.length > 0) {
                    StringBuilder sb = new StringBuilder();
                    for (String tag : tags) {
                        if (StringUtils.hasLength(tag)) {
                            sb.append(tag).append(";");
                        }
                    }
                    if (StringUtils.hasText(sb)) {
                        sb.deleteCharAt(sb.length() - 1);
                        title = title + sb + " - ";
                    }
                }
            }
        } catch (Exception e) {
            log.error("获取controller类说明失败 : {}", e.getMessage());
        }
        try {
            // 方法说明
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            boolean hasTitle = method.isAnnotationPresent(ApiOperation.class);
            if (hasTitle) {
                ApiOperation annotation = method.getAnnotation(ApiOperation.class);
                title = title + annotation.value() + " ";
            }
            if (StringUtils.hasLength(title) && title.lastIndexOf(" - ") == title.length() - 3) {
                title = title.substring(0, title.length() - 3);
            }
        } catch (Exception e) {
            log.error("获取controller方法说明失败 : {}", e.getMessage());
        }
        return title;
    }

    @Deprecated
    private String getParamMeter(HttpServletRequest request) {
        Map<String, String[]> parameterMap = request.getParameterMap();
        StringBuilder paramMap = new StringBuilder();
        if (!CollectionUtils.isEmpty(parameterMap)) {
            JSONObject param = new JSONObject();
            Set<String> keySet = parameterMap.keySet();
            for (String key : keySet) {
                String[] strings = parameterMap.get(key);
                if (strings.length > 0) {
                    param.put(key, strings[0]);
                }
            }
            if (!CollectionUtils.isEmpty(param)) {
                paramMap.append("parameterMap: [{").append(param.toJSONString()).append("}] ");
            }
        }
        return paramMap.toString();
    }
}
